package com.nny.alarm.view;

import com.nny.alarm.R;
import com.uxwine.util.Log;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.MeasureSpec;
import android.widget.Toast;

public class MarkerLayer extends View {

	BitmapDrawable[] mMarkers;
	MarkerEventListener mListener;
	boolean mbDragging;
	private float mfBearing;
	private float mfRadiusRate = 360.0f / 568.0f;
	private float mfWidthRate = 80.0f / 568.0f;
	private float mfMarkerWidth = 0.0f;
	private Point mCenter;

	private static final String TAG = MarkerLayer.class.getName();

	public MarkerLayer(Context context, AttributeSet attrs) {
		super(context, attrs);
		initView(context);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		int measureWidth = measure(widthMeasureSpec);
		int measureHeight = measure(heightMeasureSpec);

		int d = Math.min(measureWidth, measureHeight);
		setMeasuredDimension(d, d);
		mfMarkerWidth = ((float)d) * mfWidthRate;
	}

	@Override
	protected void onDraw(Canvas canvas) {
		int height = getMeasuredHeight();
		int width = getMeasuredWidth();

		int px = width / 2;
		int py = height / 2;
		mCenter.x = px;
		mCenter.y = py;
		
		int markerWidth = (int)(width * mfWidthRate / 2);
		int markerHeight = (int)(height * mfRadiusRate / 2);
		
		int markerX = px - markerWidth / 2;
		int markerY = py - markerHeight;
		
		BitmapDrawable bd = mMarkers[mbDragging ? 1 : 0];
		
		float b = mfBearing;
		bd.setBounds(markerX, markerY, markerX + markerWidth, markerY + markerHeight);		
		canvas.save();
		if(mfBearing == 180.0f)
		{
			b = 179.5f; 
		}
		canvas.rotate(b, px, py);
		bd.draw(canvas);		
		canvas.restore();
	}
	
	protected int measure(int nMeasureSpec) {
		int result = 0;
		int specMode = MeasureSpec.getMode(nMeasureSpec);
		int specSize = MeasureSpec.getSize(nMeasureSpec);

		if (specMode == MeasureSpec.UNSPECIFIED) {
			result = 200;
		} else {
			result = specSize;
		}
		return result;
	}

	public void setRate(float widthRate, float radiusRate)
	{
		mfWidthRate = widthRate;
		mfRadiusRate = radiusRate;
	}
	
	public void setOnMarkEventListener(MarkerEventListener l)
	{
		mListener = l;
	}
	
	public void setBearing(float bearing)
	{
		mfBearing = bearing;
	}
	
	void initView(Context context) {
		setFocusable(true);
		setSoftwareMode();

		Resources res = getResources();
		mMarkers = new BitmapDrawable[2];
		mMarkers[0] = (BitmapDrawable)res.getDrawable(R.drawable.time_dial_marker_normal);
		mMarkers[1] = (BitmapDrawable)res.getDrawable(R.drawable.time_dial_marker_pressed);		
		mCenter = new Point();
		mbDragging = false;
	}

	@SuppressLint("NewApi")
	public void setSoftwareMode() {
		if (android.os.Build.VERSION.SDK_INT >= 11) {
			setLayerType(View.LAYER_TYPE_SOFTWARE, null);
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if(event.getAction() == MotionEvent.ACTION_DOWN)
		{
			if(isIgnoreEvent(event.getX(), event.getY()))
				return false;
		}
		return handTouchEvent(event);
	}
	
	public boolean handTouchEvent(MotionEvent e)
	{
		int action = e.getAction();
		float x = e.getX();
		float y = e.getY();
		
		switch(action)
		{
		case MotionEvent.ACTION_DOWN:
		{
			if(isIgnoreEvent(x, y))
			{
				mbDragging = false;
				return false;
			}
			mbDragging = true;
			onMarkerCaptured(x, y);
			break;
		}
		case MotionEvent.ACTION_MOVE:
		{
			if(mbDragging)
			{
				onMarkerMove(x, y);
			}
			break;
		}
		case MotionEvent.ACTION_CANCEL:
		case MotionEvent.ACTION_UP:
		{
			if(mbDragging)
			{
				onMarkerRelease();
				mbDragging = false;
			}
			break;
		}
		default:
			break;
		}
		invalidate();
		return true;
	}
	
	private void onMarkerMove(float x, float y)
	{
		mfBearing = calcBearing(x, y);
		if(mListener != null)
			mListener.onMove(mfBearing);
	}
	
	private void onMarkerCaptured(float x, float y)
	{
		mfBearing = calcBearing(x, y);	
		if(mListener != null)
			mListener.onMove(mfBearing);		
	}
	
	private void onMarkerRelease()
	{
		if(mListener != null)
			mListener.onMarked();
	}
	
	private boolean isIgnoreEvent(float x, float y)
	{
		int length = getMeasuredHeight();
		int l = (int)(length * mfRadiusRate / 2);
		float dx = x - mCenter.x;
		float dy = y - mCenter.y;
		
		//不在两条直线中间
		if(!inArea(mfMarkerWidth, x, y, dx, dy, mfBearing))
			return true;
		
		//在圆形内部还是外面
		return (l * l < dx * dx + dy * dy);
	}
	
	private boolean inArea(float r, float x, float y, float dx, float dy, float angel)
	{
		if(angel == 0 || angel == 360)
		{
			if(!((dx >= - r) && (dx <= r)))
				return false;
			return dy < 0;
		}
		if(angel == 90)
		{
			if(!((dy >= - r) && (dy <= r)))
				return false;
			return dx > 0;
		}
		
		if(angel == 180)
		{
			if(! ((dx >= - r) && (dx <= r)))
				return false;
			return dy > 0;
		}
		
		if(angel == 270)
		{
			if(! ((dy >= - r) && (dy <= r)))
				return false;
			return dx < 0;
		}

		
		if(angel > 0 && angel < 90)//第一象限
		{
			if(dx < 0 || dy > 0)
				return false;
			
			double cotA = 1 / Math.tan((angel * Math.PI) / 180.0d);
			double sinA = Math.sin(angel * Math.PI / 180.0d);
			
			return ((-dy - (cotA * dx - r / sinA) > 0) && (-dy - (cotA * dx + r / sinA) < 0));
		}
		else if(angel > 90 && angel < 180)
		{
			if(dx < 0 || dy < 0)
				return false;
			
			double cotA = 1 / Math.tan((angel * Math.PI) / 180.0d);
			double sinA = Math.sin(angel * Math.PI / 180.0d);
			
			return ((-dy - (cotA * dx - r / sinA) > 0) && (-dy - (cotA * dx + r / sinA) < 0));
		}
		else if(angel > 180 && angel < 270)
		{
			if(dx > 0 || dy < 0)
				return false;
			
			angel -= 180;
			double cotA = 1 / Math.tan((angel * Math.PI) / 180.0d);
			double sinA = Math.sin(angel * Math.PI / 180.0d);
			
			return ((-dy - (cotA * dx - r / sinA) > 0) && (-dy - (cotA * dx + r / sinA) < 0));			
		}
		else if(angel > 270 && angel < 360)
		{
			if(dx > 0 || dy > 0)
				return false;
			
			angel -= 180;
			double cotA = 1 / Math.tan((angel * Math.PI) / 180.0d);
			double sinA = Math.sin(angel * Math.PI / 180.0d);
			
			return ((-dy - (cotA * dx - r / sinA) > 0) && (-dy - (cotA * dx + r / sinA) < 0));
		}
		
		return false;
	}
	
	
	protected float calcBearing(float x, float y) {

		double p = Math.atan2(mCenter.x - x, mCenter.y - y);
		if (p <= 0)
			return (float) (-p * 180 / Math.PI);
		else
			return (float) ((2 * Math.PI - p) * 180 / Math.PI);
	}	

	public static interface MarkerEventListener {
		public boolean onMove(float bearing);
		public void onMarked();
	}
}
